package com.yvtian.aspect;

import com.google.gson.Gson;
import com.yvtian.admin.pojo.SysLog;
import com.yvtian.annotation.Log;
import com.yvtian.constants.TokenConstants;
import com.yvtian.entity.Result;
import com.yvtian.utils.AsyncUtil;
import com.yvtian.utils.StringHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Slf4j
@Component
@Aspect
@Order(value = 100)
public class LogAspect {

    @Autowired
    private AsyncUtil asyncUtil;
    private Gson gson = new Gson();
    private final ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    @Pointcut("@annotation(com.yvtian.annotation.Log)")
    public void pointCut() {
    }

    @After(value = "pointCut()")
    public void after() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        threadLocal.set(System.currentTimeMillis());
        return joinPoint.proceed();
    }

    /**
     * controller和JoinPoint里面获取到的Log是同一个
     */
    @AfterReturning(value = "pointCut() && @annotation(controllerLog)", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Log controllerLog, Object result) {
        handlerLog(joinPoint, controllerLog, null, result);
    }

    @AfterThrowing(value = "pointCut() && @annotation(controllerLog)", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handlerLog(joinPoint, controllerLog, e, null);
    }

    /**
     * 操作日志存储
     */
    private void handlerLog(JoinPoint joinPoint, Log controllerLog, Exception e, Object result) {
        int costTime = (int) (System.currentTimeMillis() - threadLocal.get());
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        HttpServletRequest request = requestAttributes.getRequest();
        String requestURI = request.getRequestURI();
        Method method = signature.getMethod();
        String content = controllerLog.value();
        String methodName = method.getName();
        String requestType = request.getMethod();
        String userId = (String) request.getAttribute(TokenConstants.JWT_USER_ID);
        log.info("请求类型->{}", requestType);
        log.info("请求URL->{}", requestURI);
        log.info("操作描述->{}", content);
        log.info("操作方法->{},", methodName);
        log.info("返回数据->{}", StringHelper.getObjectValue(result));
        if (controllerLog.isSave()) {
            SysLog sysLog = new SysLog();
            sysLog.setStatus(0);
            if (e != null) {
                sysLog.setStatus(1);
                sysLog.setErrorMsg(StringHelper.substring(e.getMessage(), 0, 1000));
            }
            if (result instanceof Result) {
                //和数据库里面的varchar(1000)相同
                sysLog.setResult(StringHelper.substring(gson.toJson(result, Result.class), 0, 1000));
            } else {
                sysLog.setResult(StringHelper.substring(StringHelper.getObjectValue(result), 0, 1000));
            }
            sysLog.setOperType(controllerLog.operType().ordinal());
            sysLog.setContent(content);
            sysLog.setCostTime(costTime);
            sysLog.setOperTime(new Date());
            sysLog.setMethod(methodName);
            sysLog.setRequestType(requestType);
            sysLog.setUrl(requestURI);
            sysLog.setUserId(userId);
            String username = (String) request.getAttribute(TokenConstants.JWT_KEY_NICKNAME);
            sysLog.setUsername(username);
            asyncUtil.saveOperationLog(sysLog);
        }
    }

}
